package marco.android.CouchControl;

import android.content.Context;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.MotionEvent;

public class TouchPadPanel
{
	protected VersionedGestureDetector mDetector;
	protected Vibrator mVibe = null;
	protected Context mContext;
	
	public TouchPadPanel(Context context, AttributeSet attrs)
	{
	   	mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback(context));
		mContext = context;
		mVibe = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
	}
	
	// This is how this class calls its owner back
	public interface TouchPadPanelListener
	{
		public void onDown(float x, float y);
		public void onMove(float dx, float dy);
		public void onZoom(float scaleFactor);
		public void onUp();
		public void onDoubleTap(float x, float y);
		public void onLongPress(float x, float y);
		public void onFling(MotionEvent e1, MotionEvent e2, float vX, float vY);
	}

	private TouchPadPanelListener mListener;
	
	public void SetListener(TouchPadPanelListener listener)
	{
		mListener = listener;
	}
	
	// This is how the surface connected to the
	// touch pad logic gets notified of motion/touch
	// events. For better performance, this interface
	// should connect to an object that can handle
	// the callback in a separate thread so that these
	// calls can set a state and return and not have
	// to wait until the drawing surface completes
	// to continue execution.
	public interface TouchPadToSurfaceListener
	{
		public void onDown(float x, float y);
		public boolean isWithinBounds(float x, float y, float z);
		public void onDrag(float dx, float dy);
		public void onScale(float scaleFactor, float focusX, float focusY);
		public void onUp(float x, float y);
		public void onDoubleTap(float x, float y);
		public void onFling(float dx, float dy, long durationMilliSecs);
		public void onLongPress(float x, float y);
	}
	
	private TouchPadToSurfaceListener mSurfaceListener;
	public void SetDrawingListener(TouchPadToSurfaceListener listener)
	{
		mSurfaceListener = listener;
	}
	
	// This is where this class receives gesture events from the system
	private class GestureCallback implements VersionedGestureDetector.OnGestureListener, OnDoubleTapListener
	{
		private int mSwipeMinDistance;
		private int mSwipeThresholdVelocity;
		private int mSwipeMaxOffPath;
		
		public GestureCallback(Context context)
		{
//			final ViewConfiguration vc = ViewConfiguration.get(getContext());
//			mSwipeMinDistance = vc.getScaledPagingTouchSlop();
//			mSwipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
//			mSwipeMaxOffPath = vc.getScaledTouchSlop();
			
			final int SWIPE_MIN_DISTANCE = 120;
		    final int SWIPE_MAX_OFF_PATH = 250;
		    final int SWIPE_THRESHOLD_VELOCITY = 200;
			DisplayMetrics dm = context.getResources().getDisplayMetrics();
			mSwipeMinDistance = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);
			mSwipeMaxOffPath = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);
			mSwipeThresholdVelocity = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);
		}
		
		private float mX, mY;
		@Override
		public void onDown(float x, float y)
		{
			mX = x;
			mY = y;
			// TODO Auto-generated method stub
			mSurfaceListener.onDown(x, y);
		}
		
		private boolean mVibeOn = false;
		public void onDrag(float dx, float dy)
		{
			mX += dx;
			mY += dy;
			if(!mSurfaceListener.isWithinBounds(mX, mY, 0f) &&
			   mVibeOn == false)
			{
				mVibe.vibrate(30);
				mVibeOn = true;
			}
			else if(mSurfaceListener.isWithinBounds(mX, mY, 0f))
			{
				mVibeOn = false;
			}
			
			mSurfaceListener.onDrag(dx, dy);
			mListener.onMove(dx, dy);
		}

		//private float mPastScaleFactor = 1.f;
		public void onScale(float scaleFactor, float focusX, float focusY)
		{
			//if(Math.abs(scaleFactor - mPastScaleFactor) > 0.0)
			{
			   mSurfaceListener.onScale(scaleFactor, focusX, focusY);
			   mListener.onZoom(scaleFactor);
			   //mPastScaleFactor = scaleFactor;
			}
		}

		@Override
		public void onUp(float x, float y)
		{
			mVibeOn = false;
			mSurfaceListener.onUp(x, y);
			mListener.onUp();
		}

		@Override
		public boolean onDoubleTap(MotionEvent e)
		{
			mSurfaceListener.onDoubleTap(e.getX(), e.getY());
			mListener.onDoubleTap(e.getX(), e.getY());
			return true;
		}

		@Override
		public boolean onDoubleTapEvent(MotionEvent e)
		{
			return false;
		}

		@Override
		public boolean onSingleTapConfirmed(MotionEvent e)
		{
			return false;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
		{
			try
			{
				final float dt = 0.15f;
				final float dx = dt * velocityX / 2.f;
				final float dy = dt * velocityY / 2.f;
				
				mSurfaceListener.onFling(dx, dy, (long)(1000 * dt));
//				if(Math.abs(e1.getY() - e2.getY()) > mSwipeMaxOffPath)
//				{
//					// swipe that had a large vertical component
//					return false;
//				}
//				else if((e1.getX() - e2.getX()) > mSwipeMinDistance &&
//						Math.abs(velocityX) > mSwipeThresholdVelocity)
//				{
//					// Left swipe
//					mListener.onFling(e1, e2, velocityX, velocityY);
//					return(true);
//				}
//				else if((e2.getX() - e1.getX()) > mSwipeMinDistance &&
//						Math.abs(velocityX) > mSwipeThresholdVelocity)
//				{
//					// Right swipe
//					mListener.onFling(e1, e2, velocityX, velocityY);
//					return(true);
//				}
			}
			catch(Exception e)
			{
				
			}
			return false;
		}

		@Override
		public void onLongPress(MotionEvent e)
		{
			mSurfaceListener.onLongPress(e.getX(), e.getY());
			mListener.onLongPress(e.getX(), e.getY());
		}
	}
	
	public boolean onTouchEvent(MotionEvent event)
	{
		return(mDetector.onTouchEvent(event));
	}
	
//	public Bitmap GetImage()
//	{
//		// TODO Auto-generated method stub
//		return(Bitmap.createBitmap(mBitmap, mSigBoxX, mSigBoxY, mSigBoxW - mSigBoxX, mSigBoxH - mSigBoxY));
//	}
}
